package com.ec.system.modules.sys.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ec.common.constant.CommonConstant;
import com.ec.core.common.constants.TenantConstant;
import com.ec.core.common.core.base.BasePageVO;
import com.ec.core.common.enums.GlobalResponseResultEnum;
import com.ec.core.common.exception.BizException;
import com.ec.core.common.utils.BeanUtilEx;
import com.ec.core.common.utils.CoreGenerateIdUtil;
import com.ec.core.common.utils.CoreMd5Util;
import com.ec.core.mybatis.utils.CorePageUtil;
import com.ec.core.redis.utils.CoreRedisUtil;
import com.ec.core.secure.utils.SecureUtil;
import com.ec.system.api.modules.sys.bo.SysUserLoginBO;
import com.ec.system.api.modules.sys.dto.SysUserLoginDTO;
import com.ec.system.common.enums.RespResultEnum;
import com.ec.system.modules.sys.dto.PersonalInfoDTO;
import com.ec.system.modules.sys.dto.QueryUserDTO;
import com.ec.system.modules.sys.dto.ResetPasswordDTO;
import com.ec.system.modules.sys.dto.SysUserDTO;
import com.ec.system.modules.sys.entity.*;
import com.ec.system.modules.sys.mapper.SysTenantMapper;
import com.ec.system.modules.sys.mapper.SysUserMapper;
import com.ec.system.modules.sys.service.ISysDeptService;
import com.ec.system.modules.sys.service.ISysRoleService;
import com.ec.system.modules.sys.service.ISysRoleUserService;
import com.ec.system.modules.sys.service.ISysUserService;
import com.ec.system.modules.sys.vo.SysUserDetailVO;
import com.ec.system.modules.sys.vo.SysUserVO;
import com.google.common.collect.Lists;
import org.springframework.beans.BeanUtils;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @description:
 * @author: Eric Lee
 * @time: 2021/7/16 19:36
 */
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {

    @Resource
    private SysTenantMapper sysTenantMapper;
    @Resource
    private ISysRoleUserService sysRoleUserService;
    @Resource
    private ISysRoleService sysRoleService;
    @Resource
    private ISysDeptService sysDeptService;

    @Override
    public BasePageVO<SysUserVO> listUser(QueryUserDTO queryUserDTO) {
        if (!SecureUtil.isHeadquarters() || Objects.isNull(queryUserDTO.getDeptId())) {
            queryUserDTO.setTenantId(SecureUtil.userTenantId());
        }
        List<Long> allChildDepts = Lists.newArrayList();
        if (!Objects.isNull(queryUserDTO.getDeptId())) {
            List<SysDept> allDept = sysDeptService.findTenantDeptNodes(queryUserDTO.getDeptId(), queryUserDTO.getTenantId());
            this.findChildNodes(allDept, queryUserDTO.getDeptId(), allChildDepts);
            allChildDepts.add(queryUserDTO.getDeptId());
        }
        List<SysUserVO> list = baseMapper.listUser(queryUserDTO, allChildDepts);
        CoreRedisUtil.del("");
        return CorePageUtil.buildPageResult(list, list.size(), SysUserVO.class);
    }

    @Override
    public SysUserDetailVO getUserDetail(SysUserDTO userDTO) {
        QueryWrapper<SysUser> query = Wrappers.query();
        query.select("user_avatar", "user_sex", "user_birthday", "user_mobile", "user_real_name", "user_name");
        query.eq("user_id", userDTO.getUserId());
        if (!SecureUtil.isHeadquarters()) {
            query.eq("tenant_id", SecureUtil.userTenantId());
        }
        SysUser SysUser = baseMapper.selectOne(query);
        SysUserDetailVO sysUserDetailVO = new SysUserDetailVO();
        if (Objects.isNull(SysUser)) {
            return sysUserDetailVO;
        }
        BeanUtilEx.copyProperties(SysUser, sysUserDetailVO);
        return sysUserDetailVO;
    }

    @Override
    public SysUserDetailVO checkUserInfo(SysUserDTO userDTO) {
        return getUserDetail(userDTO);

    }

    private void findChildNodes(List<SysDept> list, Long parentId, List<Long> allChildDepts) {
        for (SysDept sysDeptEntity : list) {
            if (Objects.equals(parentId, sysDeptEntity.getParentId())) {
                allChildDepts.add(sysDeptEntity.getDeptId());
                findChildNodes(list, sysDeptEntity.getDeptId(), allChildDepts);
            }
        }
    }

    @Override
    public SysUserLoginBO querySysUserInfo(SysUserLoginDTO sysUserLoginDTO) {
        return baseMapper.querySysUserInfo(sysUserLoginDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteUser(SysUserDTO userDTO) {
        Long tenantId = SecureUtil.userTenantId();
        List<String> roleCodeList = sysRoleUserService.queryRoleCodeByUserId(userDTO.getUserId());
        if (roleCodeList.contains(TenantConstant.SUPER_ADMINISTRATOR) || roleCodeList.contains(TenantConstant.TENANT_ADMINISTRATOR)) {
            throw new BizException(GlobalResponseResultEnum.OPERATING_SYS_DATA_CANNOT_ERROR);
        }
        if (SecureUtil.isHeadquarters()) {
            if (!Objects.isNull(userDTO.getTenantId())) {
                tenantId = userDTO.getTenantId();
            }
        }
        LambdaUpdateWrapper<SysUser> wrapper = Wrappers.<SysUser>lambdaUpdate()
                .eq(SysUser::getUserId, userDTO.getUserId())
                .eq(SysUser::getTenantId, tenantId);
        return remove(wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addUser(SysUserDTO userDTO) {
        long count = baseMapper.selectCount(Wrappers.<SysUser>query().lambda()
                .eq(SysUser::getUserAccount, userDTO.getUserAccount()));
        if (count > 0) {
            throw new BizException(RespResultEnum.USER_ALREADY_EXISTS_ERROR);
        }
        SysUser SysUser = new SysUser();
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        userDTO.setUserPassword(bCryptPasswordEncoder.encode(userDTO.getUserPassword()));
        BeanUtils.copyProperties(userDTO, SysUser);
        SysUser.setTenantId(SecureUtil.userTenantId());
        if (SecureUtil.isHeadquarters()) {
            if (!Objects.isNull(userDTO.getTenantId())) {
                SysUser.setTenantId(userDTO.getTenantId());
            }
        }
        this.save(SysUser);
        addBatchRole(userDTO, SysUser);
        return true;
    }

    private void addBatchRole(SysUserDTO userDTO, SysUser sysUser) {
        QueryWrapper<SysRole> queryRole = Wrappers.query();
        queryRole.select("role_id");
        queryRole.eq("tenant_id", userDTO.getTenantId());
        queryRole.in("role_code", TenantConstant.SUPER_ADMINISTRATOR, TenantConstant.TENANT_ADMINISTRATOR);
        List<Long> sysRoleIds = sysRoleService.list(queryRole).stream().map(SysRole::getRoleId).collect(Collectors.toList());
        // 为了安全，排除掉前端传的系统角色
        List<Long> roleIdList = userDTO.getRoleIds().stream().mapToLong(Long::parseLong).boxed().filter(e -> !sysRoleIds.contains(e)).collect(Collectors.toList());
        List<SysRoleUser> roleUserEntityList = roleIdList.stream().map(e -> {
            SysRoleUser sysRoleUser = new SysRoleUser();
            sysRoleUser.setUserId(sysUser.getUserId());
            sysRoleUser.setRoleId(e);
            return sysRoleUser;
        }).collect(Collectors.toList());
        sysRoleUserService.saveBatch(roleUserEntityList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateUser(SysUserDTO userDTO) {
        SysUser sysUser = new SysUser();
        sysUser.setDeptId(userDTO.getDeptId());
        sysUser.setUserName(userDTO.getUserName());
        sysUser.setUserRealName(userDTO.getUserRealName());
        sysUser.setUserSex(userDTO.getUserSex());
        sysUser.setUserMobile(userDTO.getUserMobile());
        sysUser.setPostId(userDTO.getPostId());
        sysUser.setUserBirthday(userDTO.getUserBirthday());
        sysUser.setUserId(userDTO.getUserId());
        UpdateWrapper<SysUser> updateWrapper = Wrappers.update();
        updateWrapper.eq("user_id", userDTO.getUserId());
        Long tenantId = SecureUtil.userTenantId();
        if (SecureUtil.isHeadquarters()) {
            if (!Objects.isNull(userDTO.getTenantId())) {
                tenantId = userDTO.getTenantId();
            }
        }
        updateWrapper.eq("tenant_id", tenantId);
        this.update(sysUser, updateWrapper);
        List<String> roleCodeList = sysRoleUserService.queryRoleCodeByUserId(userDTO.getUserId());
        if (!roleCodeList.contains(TenantConstant.SUPER_ADMINISTRATOR) && !roleCodeList.contains(TenantConstant.TENANT_ADMINISTRATOR)) {
            // 删除用户所有的角色
            LambdaUpdateWrapper<SysRoleUser> delWrapper = Wrappers.<SysRoleUser>lambdaUpdate()
                    .eq(SysRoleUser::getUserId, userDTO.getUserId());
            sysRoleUserService.getBaseMapper().delete(delWrapper);
            // 重新添加更新后的角色
            addBatchRole(userDTO, sysUser);
        }
        return true;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean resetPassword(ResetPasswordDTO resetPasswordDTO) {
        Long userId = SecureUtil.getUser().getUserId();
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        SysUser sysUser = baseMapper.selectOne(Wrappers.<SysUser>query().lambda().eq(SysUser::getUserId, userId));
        if (!bCryptPasswordEncoder.matches(resetPasswordDTO.getOldPassword(), sysUser.getUserPassword())) {
            throw new BizException(RespResultEnum.ORIGINAL_PASSWORD_NOT_MATCH_ERROR);
        }
        LambdaUpdateWrapper<SysUser> updateWrapper = Wrappers.<SysUser>lambdaUpdate()
                .set(SysUser::getUserPassword, bCryptPasswordEncoder.encode(resetPasswordDTO.getNewPassword()))
                .eq(SysUser::getUserId, userId)
                .eq(SysUser::getTenantId, SecureUtil.userTenantId());
        return this.update(updateWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean modifiedPassword(ResetPasswordDTO resetPasswordDTO) {
        if (Objects.isNull(resetPasswordDTO.getUserId()) || Objects.isNull(resetPasswordDTO.getNewPassword())) {
            throw new BizException(GlobalResponseResultEnum.PARAM_MISS_ERROR);
        }
        List<String> roleCodeList = sysRoleUserService.queryRoleCodeByUserId(resetPasswordDTO.getUserId());
        if (roleCodeList.contains(TenantConstant.SUPER_ADMINISTRATOR)) {
            throw new BizException(GlobalResponseResultEnum.OPERATING_SYS_DATA_CANNOT_ERROR);
        }
        if (!SecureUtil.isHeadquarters() && roleCodeList.contains(TenantConstant.TENANT_ADMINISTRATOR)) {
            throw new BizException(GlobalResponseResultEnum.OPERATING_SYS_DATA_CANNOT_ERROR);
        }

        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        UpdateWrapper<SysUser> updateWrapper = Wrappers.update();
        SysUser SysUser = new SysUser();
        SysUser.setUserPassword(bCryptPasswordEncoder.encode(resetPasswordDTO.getNewPassword()));
        updateWrapper.eq("user_id", resetPasswordDTO.getUserId());
        if (!SecureUtil.isHeadquarters()) {
            updateWrapper.eq("tenant_id", SecureUtil.userTenantId());
        }
        return this.update(SysUser, updateWrapper);
    }

    @Override
    public int userCount(Long tenantId) {
        return baseMapper.selectCount(Wrappers.<SysUser>query().lambda().eq(SysUser::getTenantId, tenantId)).intValue();
    }

    @Override
    public String generateAccount(SysUserDTO userDTO) {
        if (Objects.isNull(userDTO.getTenantId())) {
            throw new BizException(GlobalResponseResultEnum.PARAM_MISS_ERROR.getCode(), "tenantId不能为空");
        }
        Long tenantId = SecureUtil.isHeadquarters() ? SecureUtil.userTenantId() : userDTO.getTenantId();
//        Long tenantId = SecureUtil.isHeadquarters() ? userDTO.getTenantId() : SecureUtil.userTenantId();
        int count = userCount(tenantId);
        SysTenant SysTenant = sysTenantMapper.selectById(tenantId);
        return CoreGenerateIdUtil.userAccount(SysTenant.getAccountPrefix(), 6, count + 1);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean changeUserStatus(Long userId, Integer userStatus) {
        if (Objects.isNull(userId) || Objects.isNull(userStatus)) {
            throw new BizException(GlobalResponseResultEnum.PARAM_MISS_ERROR);
        }
        List<String> roleCodeList = sysRoleUserService.queryRoleCodeByUserId(userId);
        if (roleCodeList.contains(TenantConstant.SUPER_ADMINISTRATOR) || roleCodeList.contains(TenantConstant.TENANT_ADMINISTRATOR)) {
            throw new BizException(GlobalResponseResultEnum.OPERATING_SYS_DATA_CANNOT_ERROR);
        }
        UpdateWrapper<SysUser> updateWrapper = Wrappers.update();
        SysUser SysUser = new SysUser();
        SysUser.setUserStatus(userStatus);
        updateWrapper.eq("user_id", userId);
        if (!SecureUtil.isHeadquarters()) {
            updateWrapper.eq("tenant_id", SecureUtil.userTenantId());
        }
        return this.update(SysUser, updateWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean modifiedPersonalInfo(PersonalInfoDTO personalInfoDTO) {
        LambdaUpdateWrapper<SysUser> updateWrapper = Wrappers.<SysUser>lambdaUpdate()
                .set(SysUser::getUserName, personalInfoDTO.getUserName())
                .set(SysUser::getUserRealName, personalInfoDTO.getUserRealName())
                .set(SysUser::getUserBirthday, personalInfoDTO.getUserBirthday())
                .set(SysUser::getUserSex, personalInfoDTO.getUserSex())
                .set(SysUser::getUserMobile, personalInfoDTO.getUserMobile())
                .eq(SysUser::getUserId, SecureUtil.getUser().getUserId());
        return this.update(updateWrapper);
    }
}
